﻿using System;
using System.Collections.Generic;
using System.Linq;
using Flurl;
using Newtonsoft.Json;
using ZilLion.Core.ConfigManager.Manager;
using ZilLion.Core.Unities.UnitiesMethods;
using ZilLion.TPO2O.SDK.EntityBase;

namespace ZilLion.TPO2O.SDK
{
    /// <summary>
    ///     token容器 线程安全
    /// </summary>
    public class TokenContainer : IDisposable
    {
        private readonly IList<KeyValuePair<TokenRequestConfig, TokenResponse>> _currenttokenDic =
            new List<KeyValuePair<TokenRequestConfig, TokenResponse>>();

        private readonly object _lockobj = new object();

        ~TokenContainer()
        {
            Dispose();
        }


        private void RefreshToken(TokenRequestConfig tokenRequestConfig)
        {
            if (tokenRequestConfig == null) return;

            #region 生成Token

            var exp =
                Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds +
                           60).ToInt32();


//"示例一：O2O物流订单业务。
//假设：企业在有赞开设了两个店铺，在美团开设了两个店铺；有赞平台的授权是对每个店铺分别授权；美团平台则是同一企业的所有店铺一次授权；
//正确的配置方式：
//UC|O2O物流订单|有赞门店1|有赞|XXXXX
//UC|O2O物流订单|有赞门店2|有赞|YYYYY
//UC|O2O物流订单|空|美团|ZZZZZ"

            var payload = new Dictionary<string, dynamic>
                {
                    {"exp", exp}, //过期时间（秒）
                    {"zlapptype", tokenRequestConfig.ZlAppType}, //商周应用程序的识别码
                    {"zlauthkey", tokenRequestConfig.ZlAuthkey}, //商周应用操作（第三方的）主体的识别码,
                    {"tpapptype", tokenRequestConfig.TpApptype} //三方平台类型的识别码
                }
                ;

            var token = JwtTokenUtility.EncodeJwtToken(payload, ZilLionConfigurationManager.GetConfigInstance<Tpo2OSdkConfig>().ZlUserSecret);
            var url = Url.Combine(ZilLionConfigurationManager.GetConfigInstance<Tpo2OSdkConfig>().ProxyHost, "Api",
                "JwtDistribute", "CreateToken", token,
                tokenRequestConfig.ZlUserCode);
            var response = HttpHelper.HttpRequestGet<TokenResponse>(url);

            #endregion

            if (response == null) return;
            lock (_lockobj)
            {
                if (!_currenttokenDic.Any(x => x.Key.Equals(tokenRequestConfig)))
                    _currenttokenDic.Add(new KeyValuePair<TokenRequestConfig, TokenResponse>(tokenRequestConfig,
                        response));
            }
        }


        private TokenResponse TryGetTokenResponse(TokenRequestConfig tokenRequestConfig)
        {
            TokenResponse result = null;
            if (_currenttokenDic == null) return result;
            lock (_lockobj)
            {
                result = _currenttokenDic.FirstOrDefault(x => x.Key.Equals(tokenRequestConfig)).Value;
            }

            return result;
        }

        /// <summary>
        ///     判断token是否合法
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private bool checktoken(TokenResponse token)
        {
            if (token == null)
                return false;
            var nowutc = Math.Round(
                (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
                .TotalSeconds
            ).ToLongOrDefault();

            var isexp = token.Exp - 60 > nowutc; //提前60s刷新


            return !isexp;
        }

        public string TryGetToken(TokenRequestConfig tokenRequestConfig)
        {
            var tokenInfo = TryGetTokenResponse(tokenRequestConfig);
            if (checktoken(tokenInfo))
                return tokenInfo.Token;
            lock (_lockobj)
            {
                RefreshToken(tokenRequestConfig);
            }
            var result = TryGetTokenResponse(tokenRequestConfig);
            if (result == null)
                throw new Exception($"{tokenRequestConfig}获取Token失败！");
            return result.Token;
        }

        #region Singleton

        private static TokenContainer _instance;
        private static readonly object Instancelocker = new object();

        private TokenContainer()
        {
        }

        public static TokenContainer Instance()
        {
            //没有第一重 instance == null 的话，每一次有线程进入 GetInstance()时，均会执行锁定操作来实现线程同步，
            //非常耗费性能 增加第一重instance ==null 成立时的情况下执行一次锁定以实现线程同步
            if (_instance == null)
                lock (Instancelocker)
                {
                    //Double-Check Locking 双重检查锁定
                    if (_instance == null) _instance = new TokenContainer();
                }
            return _instance;
        }

        public void Dispose()
        {
            _currenttokenDic.Clear();
        }

        #endregion
    }


    public class TokenRequestConfig
    {
        /// <summary>
        ///     商周客户的注册编号()
        /// </summary>
        public string ZlUserCode { get; set; }

        /// <summary>
        ///     商周应用程序的识别码
        /// </summary>
        public string ZlAppType { get; set; }

        /// <summary>
        ///     商周应用操作（第三方的）主体的识别码
        /// </summary>
        public string ZlAuthkey { get; set; }

        /// <summary>
        ///     第三方平台类型的识别码
        /// </summary>
        public string TpApptype { get; set; }


        public override bool Equals(object obj)
        {
            var other = obj as TokenRequestConfig;
            return other != null && Equals(other);
        }


        protected bool Equals(TokenRequestConfig other)
        {
            return ZlUserCode == other.ZlUserCode && ZlAppType == other.ZlAppType &&
                   ZlAuthkey == other.ZlAuthkey && TpApptype == other.TpApptype;
        }

        public override string ToString()
        {
            return JsonConvert.SerializeObject(this);
        }
    }
}